/**
 * \file net_lproto.h
 *
 * \brief kcp + sockets + mbedtls
 */
/*
 *  Copyright (C) 2006-2018, ARM Limited, All Rights Reserved
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This file is part of lsukm (https://gitee.com/bytes33/lsukm)
 */
#ifndef NET_PROTO_H
#define NET_PROTO_H

#include "net_sockets.h"
#include "ikcp.h"

#define ERR_KCP_CREATE_FAILED                     -0x0052  /**< Failed to open a ikcp. */

#define NET_LPROTO_CONNECT  1
#define NET_LPROTO_LISTEN   2

#ifdef __cplusplus
extern "C" {
#endif

typedef int(*lproto_net_event)(void *ctx, short events, void *arg);
typedef int(*lproto_kcp_event)(void *ctx, short events, const char *buff, int len);
typedef int(*lproto_recv)(void *ctx, const char *buff, int len);

enum
{
    LPROTO_EVENT_NEW = 1,
    LPROTO_EVENT_ERR,
};

/**
 * Wrapper type for proto.
 *
 * kcp + socket + tls
 */
typedef struct net_lproto
{
    net_context             tfd;
    ikcpcb*                 pkcp;

    int                     proto;      //proto type
    int                     type;      //service type connect or listen 
    int                     hid;

    struct sockaddr_storage local;
    struct sockaddr_storage peer;

    lproto_net_event        func_net_event;
    lproto_kcp_event        func_kcp_event;
    lproto_recv             func_recv;
}
net_lproto;

/**
 * \brief          create a proto
 *
 * \return         the proto
 */
net_lproto* lproto_create( );

//lproto_mbedtls

/**
 * \brief          Initiate a ikcp with param
 *
 * \param ctx      proto to use
 * \param conv     kcp conv
 * \param sndwnd   maximum send window size
 * \param rcvwnd   maximum send window size
 * \param nodelay  0:disable(default), 1:enable
 * \param interval internal update timer interval in millisec, default is 100ms 
 * \param resend   0:disable fast resend(default), 1:enable fast resend
 * \param nc       0:normal congestion control(default), 1:disable congestion control
 *
 * \return         0 if successful, or one of:
 *                      ERR_KCP_INIT
 *
 * \note           ikcp_wndsize(kcp1, 128, 128);
 *                 ikcp_nodelay(kcp1, 0, 20, 0, 1);
 */
int lproto_ikcp( net_lproto* ctx, unsigned int conv, int sndwnd , int rcvwnd, 
    int nodelay, int interval, int resend, int nc);

/**
 * \brief          Initiate a connection with host:port in the given protocol
 *
 * \param ctx      proto to use
 * \param host     Host to connect to
 * \param port     Port to connect to
 * \param proto    Protocol: NET_PROTO_TCP or NET_PROTO_UDP 
 *
 * \return         0 if successful, or one of:
 *                      ERR_NET_SOCKET_FAILED,
 *                      ERR_NET_UNKNOWN_HOST,
 *                      ERR_NET_CONNECT_FAILED
 *
 * \note           Sets the socket in connected mode even with UDP.
 */
int lproto_connect( net_lproto *ctx, const char *host, const char *port, int proto );


/**
 * \brief          Create a receiving socket on bind_ip:port in the chosen
 *                 protocol. If bind_ip == NULL, all interfaces are bound.
 *
 * \param ctx      proto to use
 * \param bind     bind ip to bind ,can be NULL
 * \param port     prot number to use
 * \param proto    Protocol: NET_PROTO_TCP or NET_PROTO_UDP 
 *
 * \return         0 if successful, or one of:
 *                      ERR_NET_SOCKET_FAILED,
 *                      ERR_NET_BIND_FAILED,
 *                      ERR_NET_LISTEN_FAILED
 *
 * \note           Sets the socket in connected mode even with UDP.
 */
int lproto_accept(net_lproto* ctx, const char* bind, const char* port, int proto);

int lproto_output(const char* buf, int len, ikcpcb* kcp, void* user);

/**
 * \brief          Read at most 'len' characters. If no error occurs,
 *                 the actual amount read is returned.
 */
int lproto_read( net_lproto *ctx, unsigned char *buf, size_t len );

/**
 * \brief          Write at most 'len' characters. If no error occurs,
 *                 the actual amount read is returned.
 */
int lproto_send( net_lproto *ctx, const unsigned char *buf, size_t len );

/**
 * \brief          proto loop work
 */
int lproto_loop( net_lproto *ctx );

/**
 * \brief          Gracefully shutdown the connection and free associated data
 *
 * \param ctx      The context to free
 */
void lproto_free( net_lproto *ctx);


/**
 * some tool functions
 *  
 */
unsigned int    lproto_calchash(const char* s1, int len1, const char* s2, int len2);

unsigned short  lproto_getport(const struct sockaddr_storage* addr);

int             lproto_gethost(const struct sockaddr_storage* addr, char* host, int len);

#ifdef __cplusplus
}
#endif

#endif /* NET_PROTO_H */